/*
 * @Author: LVGRAPE
 * @LastEditors: LVGRAPE
 */
#include "drv_spi.h"

#define DRV_DEBUG
#define LOG_LVL DBG_LOG
#define LOG_TAG "drv.spi"
#include <rtdbg.h>

// #define spi->instance SPI1
#define BUFFER_SIZE 32

spi_dev_t *current_spi = RT_NULL;
spi_init_type spi_init_struct;

/**
 * @brief  spi configuration.
 * @param  none
 * @retval none
 */
 void spi_dev_init(spi_dev_t *spi)
{
    if (spi->instance == SPI1)
    {
        crm_periph_clock_enable(CRM_SPI1_PERIPH_CLOCK, TRUE);
        spi1_gpio_config();
    }
    else if (spi->instance == SPI2)
    {
        crm_periph_clock_enable(CRM_SPI2_PERIPH_CLOCK, TRUE);
        spi2_gpio_config();
    }

    spi_default_para_init(&spi_init_struct);

    /* data_width */
    if (spi->data_width <= 8)
    {
        spi_init_struct.frame_bit_num = SPI_FRAME_8BIT;
    }
    else if (spi->data_width <= 16)
    {
        spi_init_struct.frame_bit_num = SPI_FRAME_16BIT;
    }

    /* baudrate */
    {
        uint32_t spi_apb_clock;
        uint32_t max_hz;
        crm_clocks_freq_type clocks_struct;
        max_hz = spi->max_hz;
        crm_clocks_freq_get(&clocks_struct);

        // rt_kprintf("sys freq: %d\n", clocks_struct.sclk_freq);
        // rt_kprintf("apb1 freq: %d\n", clocks_struct.apb1_freq);
        // rt_kprintf("apb2 freq: %d\n", clocks_struct.apb2_freq);
        // rt_kprintf("max freq: %d\n", max_hz);

        spi_apb_clock = clocks_struct.apb2_freq;

        if (max_hz >= (spi_apb_clock / 2))
        {
            spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_2;
        }
        else if (max_hz >= (spi_apb_clock / 4))
        {
            spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_4;
        }
        else if (max_hz >= (spi_apb_clock / 8))
        {
            spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_8;
        }
        else if (max_hz >= (spi_apb_clock / 16))
        {
            spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_16;
        }
        else if (max_hz >= (spi_apb_clock / 32))
        {
            spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_32;
        }
        else if (max_hz >= (spi_apb_clock / 64))
        {
            spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_64;
        }
        else if (max_hz >= (spi_apb_clock / 128))
        {
            spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_128;
        }
        else
        {
            /* min prescaler 256 */
            spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_256;
        }
    } /** baudrate */

    /**mode */
    switch (spi->mode & RT_SPI_MODE_3)
    {
    case RT_SPI_MODE_0: // NOTE mode 0表示：空闲的时候是低电平，在上升沿采样
        spi_init_struct.clock_phase = SPI_CLOCK_PHASE_1EDGE;
        spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_LOW;
        break;
    case RT_SPI_MODE_1: // NOTE mode 1表示：空闲的时候是低电平，在下降沿采样
        spi_init_struct.clock_phase = SPI_CLOCK_PHASE_2EDGE;
        spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_LOW;
        break;
    case RT_SPI_MODE_2: // NOTE mode 2表示：空闲时是高电平，在下降沿采样
        spi_init_struct.clock_phase = SPI_CLOCK_PHASE_1EDGE;
        spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_HIGH;

        break;
    case RT_SPI_MODE_3: // NOTE mode 3表示：空闲的时候是高电平，在上升沿采样
        spi_init_struct.clock_phase = SPI_CLOCK_PHASE_2EDGE;
        spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_HIGH;
        break;
    }

    /* msb or lsb */
    if (spi->mode & RT_SPI_MSB)
    {
        spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_MSB;
    }
    else
    {
        spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_LSB;
    }
    spi_init_struct.transmission_mode = SPI_TRANSMIT_FULL_DUPLEX;
    spi_init_struct.master_slave_mode = SPI_MODE_MASTER;
    spi_init_struct.cs_mode_selection = SPI_CS_SOFTWARE_MODE;


    spi_enable(spi->instance, FALSE);
    spi_init(spi->instance, &spi_init_struct);
    spi_enable(spi->instance, TRUE);


    /* disable spi crc */
    spi_crc_enable(spi->instance, FALSE);

    pin_mode(spi->cs_pin, PIN_MODE_OUTPUT_PP);
    pin_write(spi->cs_pin, PIN_HIGH);

    if (pin_read(spi->cs_pin) != PIN_HIGH)
    {
        LOG_E("spi cs pin can't be set to high !!!");
    }
}

/**
 * @brief  gpio configuration.
 * @param  none
 * @retval none
 */
void spi1_gpio_config(void)
{
    gpio_init_type gpio_initstructure;

    crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
    gpio_pin_remap_config(SWJTAG_GMUX_100, TRUE); // 100：禁用 SWD 和 JTAG，所有 SWJTAG 引脚均可作GPIO；
    gpio_pin_remap_config(SPI1_GMUX_0001, TRUE);     // remap spi1 to PB.3, PB.4, PB.5

    gpio_default_para_init(&gpio_initstructure);

    /* spi1 sck pin PB.3*/
    gpio_initstructure.gpio_pins = GPIO_PINS_3 | GPIO_PINS_5;
    gpio_initstructure.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
    gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MAXIMUM;
    gpio_initstructure.gpio_pull = GPIO_PULL_NONE;
    gpio_initstructure.gpio_mode = GPIO_MODE_MUX;
    gpio_init(GPIOB, &gpio_initstructure);

    /* spi2 miso pin PB.4*/
    gpio_initstructure.gpio_pull = GPIO_PULL_NONE;
    gpio_initstructure.gpio_mode = GPIO_MODE_MUX;
    gpio_initstructure.gpio_pins = GPIO_PINS_4;
    gpio_init(GPIOB, &gpio_initstructure);

    // /* spi1 mosi pin PB.5*/
    // gpio_initstructure.gpio_pull = GPIO_PULL_DOWN;
    // gpio_initstructure.gpio_mode = GPIO_MODE_MUX;
    // gpio_initstructure.gpio_pins = GPIO_PINS_5;
    // gpio_init(GPIOB, &gpio_initstructure);


}
void spi2_gpio_config(void)
{
    gpio_init_type gpio_initstructure;

    crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_SPI2_PERIPH_CLOCK, TRUE);
    // gpio_pin_remap_config(SWJTAG_GMUX_100, TRUE); // 100：禁用 SWD 和 JTAG，所有 SWJTAG 引脚均可作GPIO；
    // gpio_pin_remap_config(SPI1_GMUX_0001, TRUE);     // remap spi1 to PB.3, PB.4, PB.5

    gpio_default_para_init(&gpio_initstructure);

    /* spi2 sck pin PB.13, mosi PB.15, cs PB.12*/
    gpio_initstructure.gpio_pins = GPIO_PINS_13 | GPIO_PINS_15;
    gpio_initstructure.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
    gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MAXIMUM;
    gpio_initstructure.gpio_pull = GPIO_PULL_NONE;
    gpio_initstructure.gpio_mode = GPIO_MODE_MUX;
    gpio_init(GPIOB, &gpio_initstructure);

    gpio_initstructure.gpio_mode = GPIO_MODE_OUTPUT;
    gpio_initstructure.gpio_pins = GPIO_PINS_12;
    gpio_init(GPIOB, &gpio_initstructure);

    /* spi2 miso pin PB.14*/
    gpio_initstructure.gpio_pull = GPIO_PULL_NONE;
    gpio_initstructure.gpio_mode = GPIO_MODE_MUX;
    gpio_initstructure.gpio_pins = GPIO_PINS_14;
    gpio_init(GPIOB, &gpio_initstructure);
}
static uint16_t _spi_receive_transmit(spi_type* instance, uint16_t dat)
{
    /* wait until the transmit buffer is empty */
    while (spi_i2s_flag_get(instance, SPI_I2S_TDBE_FLAG) == RESET)
        ;
    /* send the byte */
    spi_i2s_data_transmit(instance, dat);

    /* wait until a data is received */
    while (spi_i2s_flag_get(instance, SPI_I2S_RDBF_FLAG) == RESET)
        ;
    /* get the received data */
    return spi_i2s_data_receive(instance);
}
int spi_send_then_send(spi_dev_t *spi, uint8_t *txbuf1, uint16_t txlen1, uint8_t *txbuf2, uint16_t txlen2)
{
    if (current_spi != spi)
    {
        spi_dev_init(spi);
        current_spi = spi;
    }
    pin_write(spi->cs_pin, PIN_LOW);
    for (uint16_t i = 0; i < txlen1; i++)
    {
        _spi_receive_transmit(spi->instance, txbuf1[i]);
    }
    for (uint16_t i = 0; i < txlen2; i++)
    {
        _spi_receive_transmit(spi->instance, txbuf2[i]);
    }
    pin_write(spi->cs_pin, PIN_HIGH);
    return 0;
}
int spi_send_then_receive(spi_dev_t *spi, uint8_t *txbuf, uint16_t txlen, uint8_t *rxbuf, uint16_t rxlen)
{
    if (current_spi != spi)
    {
        spi_dev_init(spi);
        current_spi = spi;
    }
    pin_write(spi->cs_pin, PIN_LOW);
    for (uint16_t i = 0; i < txlen; i++)
    {
        _spi_receive_transmit(spi->instance, txbuf[i]);
    }
    for (uint16_t i = 0; i < rxlen; i++)
    {
        rxbuf[i] = _spi_receive_transmit(spi->instance, 0xff);
    }
    pin_write(spi->cs_pin, PIN_HIGH);
    return 0;
}
